home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The ZX Files 3
/
ZX Files 3 (Disk 2 of 3).adf
/
48KMANUAL
/
48PART2.txt
/
48PART2.txt
Wrap
Text File
|
1978-01-22
|
63KB
|
1,512 lines
CHAPTER 10
Mathematical functions
Summary
PI, EXP, LN, SIN, COS, TAN, ASN, ACS, ATN
This chapter deals with the mathematics that the ZX Spectrum
can handle. Quite possibly you will never have to use any of
this at all, so if you find it too heavy going, don't be
afraid of skipping it. It covers the operation (raising to a
power), the functions EXP and LN, and the trigonometrical
functions SIN, COS, TAN and their inverses ASN, ACS, and ATN.
^ and EXP
You can raise one number to the power of another - that means
'multiply the first number by itself the second number of
times'. This is normally shown by writing the second number
just above and to the right of the first number; but obviously
this would be difficult on a computer so we use the symbol
instead. For example, the powers of 2 are
21=2
22=2*2=4 (2 squared)
23=2*2*2=8 (2 cubed)
24=2*2*2*2=16 (2 to the power four)
Thus at its most elementary level, 'ab' means 'a multiplied
by itself b times', but obviously this only makes sense if b is
a positive whole number. To find a definition that works for
other values of b, we consider the rule
a(b+c) = ab*ac
(Notice that we give a higher priority than * and / so that
when there are several operations in one expression, the s are
evaluated before the s and /s. ) You should not need much
convincing that this works when b and c are both positive whole
numbers; but if we decide that we want it to work even when the
y are not, then we find ourselves compelled to accept that
a0 = 1
a(-b) = 1/ab
a(1/b) = the bth root of a, which is to say, the number that
you have to multiply by itself b times to get a
and
a(b*c)=(ab)c
If you have never seen any of this before then don't try to
remember it straight away; just remember that
at (-1)=1/a
and
at (1/2)=SQR a
and maybe when you are familiar with these the rest will begin
to make sense.
Experiment with all this by trying this program:
10 INPUT a,b,c
20 PRINT a(b+c),ab*ac
30 GO TO 14
Of course, if the rule we gave earlier is true, then each
time round the two numbers that the computer prints out will be
equal. (Note - because of the way the computer works out t, the
number on the left - a in this case - must never be negative.)
A rather typical example of what this function can be used
for is that of compound interest. Suppose you keep some of your
money in a building society and they give 15% interest per
year. Then after one year you will have not just the 100% that
you had anyway, but also the 15% interest that the building
society have given you, making altogether 115% of what you had
originally. To put it another way, you have multiplied your sum
of money by 1.15, and this is true however much you had there
in the first place. After another year, the same will have
happened again, so that you will then have 1.15*1.15=1.1512=1
.3225 times your original sum of money. In general, after y
years, you will have 1.15y times what you started out with.
If you try this command
FOR y=0 TO 198: PRINT y,10*1.15Y: NEXT y
you will see that even starting off from just ú10, it all
mounts up quite quickly, and what is more, it gets faster and
faster as time goes on. (Although even so, you might still find
that it doesn't keep up with inflation.)
This sort of behaviour, where after a fixed interval of time
some quantity multiplies itself by a fixed proportion, is
called exponential growth, and it is calculated by raising a
fixed number to the power of the time.
Suppose you did this:
10 DEF FN a(x)=ax
Here, a is more or less fixed, by LET statements: its value
will correspond to the interest rate, which changes only every
so often.
There is a certain value for a that makes the function FN a
look especially pretty to the trained eye of a mathematician:
and this value is called e. The ZX Spectrum has a function
called EXP defined by
EXP x=ex
Unfortunately, e itself is not an especially pretty number:
it is an infinite non-recurring decimal. You can see its first
few decimal places by doing
PRINT EXP 1
because EXP 1 = e1 = e. Of course, this is just an
approximation. You can never write down e exactly.
LN
The inverse of an exponential function is a logarithmic
function: the logarithm (to base a) of a number x is the power
to which you have to raise a to get the number x, and it is
written logax. Thus by definition alogax=x; and it is also true
that log (ax)=x.
You may well already know how to use base 10 logarithms for
doing multiplications; these are called common logarithms. The
ZX Spectrum has a function LN which calculates logarithms to
the base e; these are called natural logarithms. To calculate
logarithms to any other base, you must divide the natural
logarithm by the natural logarithm of the base:
logax = LN x/ LN a
PI
Given any circle, you can find its perimeter (the distance
round its edge; often called its circumference) by multiplying
its diameter (width) by a number called p. (p is a Greek p, and
it is used because it stands for perimeter.
Its name is pi.)
Like e, p is an infinite non-recurring decimal; it starts off
as 3.141592653589....The word PI on the Spectrum (extended
mode, then M) is taken as standing for this number - try PRINT
PI.
SIN, COS and TAN; ASN, ACS and ATN
The trigonometrical functions measure what happens when a
point moves round a circle. Here is a circle of radius 1 (1
what? It doesn't matter, as long as we keep to the same unit
all the way through. There is nothing to stop you inventing a
new unit of your own for every circle that you happen to be
interested in) and a point moving round it. The point started
at the 3 o'clock position, and then moved round in an anti-
clockwise direction.
We have also drawn in two lines called axes through the
centre of the circle. The one through 9 o'clock and 3 o'clock
is called the x-axis, and the one through 6 o'clock and 12
o'clock is called the y-axis.
To specify where the point is, you say how far it has moved
round the circle from its 3 o'clock starting position: let us
call this distance a. We know that the circumference of the
circle is 2p (because its radius is 1 and its diameter is thus
2): so when it has moved a quarter of the way round the circle,
a=p/2; when it has moved halfway round, a=p; and when it has
moved the whole way round, a=2p.
Given the curved distance round the edge, a, two other
distances you might like to know are how far the point is to
the right of the y-axis, and how far it is above the x-axis.
These are called, respectively, the cosine and sine of a. The
functions COS and SIN on the computer will calculate these.
F9Vú/(PBrush0 0 341 3298BM8>(UI8Q;%rrl
Note that if the point goes to the left of the y-axis, then
the cosine becomes negative; and if the point goes below the x-
axis, the sine becomes negative.
Another property is that once a has got up to 2p, the point
is back where it started and the sine and cosine start taking
the same values all over again
:
SIN (a+2*PI) = SIN a
COS (a+2*PI) = COS a
The tangent of a is defined to be the sine divided by the
cosine; the corresponding function on the computer is called
TAN.
Sometimes we need to work these functions out in reverse,
finding the value of a that has given sine, cosine or tangent.
The functions to do this are called arcsine (ASN on the
computer), arccosine (ACS) and arctangent (ATN).
In the diagram of the point moving round the circle, look at
the radius joining the centre to the point. You should be able
to see that the distance we have called a, the distance that
the point has moved round the edge of the circle, is a way of
measuring the angle through which the radius has moved away
from the x-axis. When a=p/2, the angle is 90 degrees; when a=p
the angle is 180 degrees; and so round to when a=2p, and the
angle is 360 degrees. You might just as well forget about
degrees, and measure the angle in terms of a alone: we say then
that we are measuring the angle in radians. Thus p/2 radians=
90 degrees and so on.
You must always remember that on the ZX Spectrum SIN, COS and
so on use radians and not degrees. To convert degrees to
radians, divide by 180 and multiply by p; to convert back from
radians to degrees, you divide by p and multiply by 180.
CHAPTER 11
Random numbers
Summary
RANDOMIZE
RND
This chapter deals with the function RND and the keyword
RANDOMIZE. They are both used in connection with random
numbers, so you must be careful not to get them mixed up. They
are both on the same key (T); RANDOMIZE has had to be
abbreviated to RAND.
In some ways RND is like a function: it does calculations and
produces a result. It is unusual in that it does not need an
argument.
Each time you use it, its result is a new random number
between 0 and 1. (Sometimes it can take the value 0, but never
1.)
Try
10 PRINT RND
20 GO TO 10
to see how the answer varies. Can you detect any pattern7 You
shouldn't be able to; 'random' means that there is no pattern.
Actually, RND is not truly random, because it follows a fixed
sequence of 65536 numbers. However, these are so thoroughly
jumbled up that there are at least no obvious patterns and we
say that RND is pseudo-random.
RND gives a random number between 0 and 1, but you can easily
get random numbers in other ranges. For instance, 5*RND is
between 0 and 5, and 1.3+0.7*RND is between 1.3 and 2. To get
whole numbers, use INT (remembering that INT always rounds
down) as in 1 +INT (RND*6), which we shall use in a program to
simulate dice. RND*6 is in the range 0 to 6, but since it never
actually reach es 6, INT (RND*6) is 0,1,2,3,4 or 5.
Here is the program:
10 REM dice throwing program
20 CLS
30 FOR n=1 TO 2
40 PRINT 1+1NT (RND*6);" ";
50 NEXT n
60 INPUT a$: GO TO 20
Press ENTER each time you want to throw the dice.
The RANDOMIZE statement is used to make RND start off at a
definite place in its sequence of numbers, as you can see with
this program:
10 RANDOMIZE 1
20 FOR n=1 TO 5: PRINT RND ,: NEXT n
30 PRINT: GO TO 10
After each execution of RANDOMIZE 1, the RND sequence starts
off again with 0.0022735596. You can use other numbers between
1 and 65535 in the RANDOMIZE statement to start the RND
sequence off at different places.
If you had a program with RND in it and it also had some
mistakes that you had not found, then it would help to use
RANDOMIZE like this so that the program behaved the same way
each time you ran it.
RANDOMIZE on its own (and RANDOMIZE 0 has the same effect) is
different, because it really does randomize RND - you can see
this in the next program.
10 RANDOMIZE
20 PRINT RND: GO TO 10
The sequence you get here is not very random, because
RANDOMIZE uses the time since the computer was switched on.
Since this has gone up by the same amount each time RANDOMIZE
is executed, the next RND does more or less the same. You
would get better randomness by replacing GO TO 10 by GO TO 20.
Note: Most dialects of BASIC use RND and RANDOMIZE to produce
random numbers, but not all use them in the same way.
Here is a program to toss coins and count the numbers of
heads and tails.
10 LET heads=0: LET tails=0
20 LET coin=lNT (RND*2)
30 IF coin=3 THEN LET heads=heads+1
40 IF coin=1 THEN LET tails=tails+1
50 PRINT heads;",";tails,
60 IF tails<>6 THEN PRINT heads/tails;
70 PRINT: GO TO 20
The ratio of heads to tails should become approximately 1 if
you go on long enough, because in the long run you expect
approximately equal numbers of heads and tails.
Exercises
1. Test this rule:
Suppose you choose a number between 1 and 872 and type
RANDOMIZE your number
Then the next value of RND will be
(75*(your number+1) -1) /65536
2. (For mathematicians only.)
Let p be a (large) prime, and let a be a primitive root
modulo p. Then if bi is the residue of ai modulo p (l ú bi ú p-
l ), the sequence
bi -1
p-1
is a cyclical sequence of p-1 distinct numbers in the range 0
to 1 (excluding 1). By choosing a suitably, these can be made
to look fairly random.
65537 is a Fermat prime, 2l6+1. Because the multiplicative
group of non-zero residues modulo 65537 has a power of 2 as its
order, a residue is a primitive root if and only if it is not a
quadratic residue. Use Gauss' law of quadratic reciprocity to
show that 75 is a primitive root modulo 65537.
The ZX Spectrum uses p=65537 and a=75, and stores some bi-l
in memory. RND entails replacing bi-1 in memory by bi+1 -1, and
yielding the result (bi+1-l) (p-l). RANDOMIZE n (with
1únú65535) makes bi equal to n+1.
RND is approximately uniformly distributed over the range 0
to 1.
CHAPTER 12
Arrays
Summary
Arrays (the way the ZX Spectrum handles string arrays is
slightly non-standard).
DIM . . .
Suppose you have a list of numbers, for instance the marks of
ten people in a class. To store them in the computer you could
set up a single variable for each person. But you would find
them very awkward. You might decide to call the variable Bloggs
1, Bloggs 2, and so on up to Bloggs 10, but the program to set
up these ten numbers would be rather long and boring to type
in.
How much nicer it would be if you could type this:
5 REM this program will not work
10 FOR n=1 TO 10
20 READ Bloggs n
30 NEXT n
40 DATA 10,2,5,19,16,3,11,1,0,6
Well you can't.
However, there is a mechanism by which you can apply this
idea, and it uses arrays. An array is a set of variables, its
elements, all with the same name , and distinguished only by a
number (the subscript) written in brackets after the name. In
our example the name could be b (like control variables of FOR
- NEXT loops, the name of an array must be a single letter),
and the ten variables would then be b(l), b(2), and so on up to
b(l0).
The elements of an array are called subscripted variables, as
opposed to the simple variables that you are already familiar
with.
Before you can use an array, you must reserve some space for
it inside the computer, and you do this using a DIM (for
dimension) statement.
DIM b(10)
sets up an array called b with dimension 10 (i.e. there are 10
subscripted variables b(1),...,b(10)) and initializes the 10
values to 0. It also deletes any array called b that existed
previously. (But not a simple variable. An array and a simple
numerical variable with the same name can coexist, and there
shouldn't be any confusion between them because the array
variable always has a subscript).
The subscript can be an arbitrary numerical expression, so now
you can write
10 FOR n=1 TO 10
20 READ b(n)
30 NEXT n
40 DATA 10,2,5,19,16,3,11,1,0,6
You can also set up arrays with more than one dimension. In a
two dimension al array you need two numbers to specify one of
the elements - rather like the line and column numbers to
specify a character position on the television screen - so it
has the form of a table. Alternatively, if you imagine the line
and column numbers (two dimensions) as referring to a printed
page, you could have an extra dimension for the page numbers.
Of course, we are talking about numeric arrays; so the elements
would not be printed characters as in a book, but numbers.
Think of the elements of a three-dimensional array v as being
specified by v (page number, line number, column number).
For example, to set up a two-dimensional array c with
dimensions 3 and 6, you use a DIM statement
DIM c(3,6)
This then gives you 3*6=18 subscripted variables
c(1 ,1),c(1 ,2), . . .,c(1,6)
c(2, 1 ),c(2,2), . . .,c(2,6)
c(3, 1 ),c(3,2), . . .,c(3,6)
The same principle works for any number of dimensions.
Although you can have a number and an array with the same
name, you cannot have two arrays with the same name, even if
they have different numbers of dimensions.
There are also string arrays. The strings in an array differ
from simple strings in that they are of fixed length and
assignment to them is always Procrustean - chopped off or
padded with spaces. Another way of thinking of them is as
arrays (with one extra dimension) of single characters. The
name of a string array is a single letter followed by $, and a
string array and a simple string variable cannot have the same
name (unlike the case for numbers).
Suppose then, that you want an array a$ of five strings. You
must decide how long these strings are to be - let us suppose
that 10 characters each is long enough. You then say
DIM a$(5,10) (type this in)
This sets up a 5*10 array of characters, but you can also
think of each row as being a string:
a$(1)=a$(1,1) a$(1,2) . . . a$(1,10)
a$(2)=a$(2,1) a$(2,2) . . . a$(2,10)
: : : :
a$(5)=a$(5,1) a$(5,2) . . . a$(5,10)
If you give the same number of subscripts (two in this case)
as there were dimensions in the DIM statement, then you get a
single character; but if you miss the last one out, then you
get a fixed length string. So, for instance, A$(2,7) is the 7th
character in the string A$(2); using the slicing notation, we
could also write this as A$(2)(7). Now type
LET a$(2)="1234567890"
and
PRINT a$(2),a$(2,7)
For the last subscript (the one you can miss out), you can
also have a slicer, so that for instance
a$(2,4 TO 8)=a$(2)(4 TO 8)="45678"
Remember:
In a string array, all the strings have the same, fixed length.
The DIM statement has an extra number (the last one) to specify
this length. When you write down a subscripted variable for a
string array, you can put in an extra number, or a slicer, to
correspond with the extra number in the DIM statement. You can
have string arrays with no dimensions. Type
DIM a$(10)
and you will find that a$ behaves just like a string variable,
except that it always has length 10, and assignment to it is
always procrustean.
Exercises
1. Use READ and DATA statements to set up an array m$ of twelve
strings in which m$(n) is the name of the nth month. (Hint: the
DIM statement will be DIM m$(12,9). Test it by printing out all
the mS(n) (use a loop).
Type
PRINT "now is the month of ";m$(5);"ing";" when merry
lads are playin
g"
What can you do about all those spaces?
CHAPTER 13
Conditions
Summary
AND, OR
NOT
We saw in Chapter 3 how an IF statement takes the form
IF condition THEN . . .
The conditions there were the relations (=, <, >, <=, >= and
<>), which compare two numbers or two strings. You can also
combine several of these, using the logical operations, AND,
OR and NOT.
One relation AND another relation is true whenever both
relations are true, so you could have a line like:
IF a$="yes" AND x>0 THEN PRINT x
in which x only gets printed if a$=''yes" and x>0. The BASIC
here is so close to English that it hardly seems worth
spelling out the:details. As in English, you can join lots of
relations together with AND, and then the whole lot is true if
all the individual relations are.
One relation OR another is true whenever at least one of the
two relations is true. (Remember that it is still true if both
the relations are true; this is something that English doesn't
always imply.)
The NOT relationship turns things upside down. The NOT
relation is true whenever the relation is false, and false
whenever it is true!
Logical expressions can be made with relations and AND, OR
and NOT, just as numerical expressions can be made with
numbers and +, - and so on; you can even put them in brackets
if necessary. They have priorities in the same way as the usual
operations +, -, *, / and , do: OR has the lowest priority,
then AND, then NOT, then the relations, and the usual
operations.
NOT is really a function, with an argument and a result, but
its priority is much lower than that of other functions.
Therefore its argument does not need brackets unless it
contains AND or OR (or both). NOT a=b means the same as
NOT (a=b) (and the same as a<>b, of course).
<> is the negation of = in the sense that it is true if, and
only if, = is false. In other words,
a<>b is the same as NOT a=b
and also
NOT a<>b is the same as a=b
Persuade yourself that >= and <= are the negations of < and >
respectively: thus you can always get rid of NOT from in front
of a relation by changing the relation.
Also,
NOT (a first logical expression AND a second)
is the same as
NOT (the first) OR NOT (the second)
and
NOT (a first logical expression OR a second)
is the same as
NOT (the first) AND NOT (the second).
Using this you can work NOTs through brackets until
eventually they are all applied to relations, and then you can
get rid of them. Logically speaking, NOT is unnecessary,
although you might still find that using it makes a program
clearer.
The following section is quite complicated, and can be
skipped by the faint hearted!
Try
PRINT 1=2,1 < >2
which you might expect to give a syntax error. In fact, as far
as the computer is concerned, there is no such thing as a
logical value: instead it uses ordinary numbers, subject to a
few rules.
(i) =, <, >, <=, >= and <> all give numeric results: 1 for
true, and 0 for false. Thus the PRINT command above printed 0
for '1=2', which is false, and 1 for '1<>2', which is true.
(ii) In
IF condition THEN . . .
the condition can be actually any numeric expression. If its
value is 0, then it counts as false, and any other value
including the value of 1 that a true relation gives) counts as
true. Thus the IF statement means exactly the same as
IF condition <>0 THEN . . .
(iii) AND, OR and NOT are also number-valued operations.
x AND y has the value {x if y is true (non-zero)
{0 (false), if y is false (zero)
x OR y has the value {1 (true), if y is true (non zero)
{x, if y is false (zero)
NOT x has the value {0 (false), if x is true (non-zero)
{1 (true), if x is false (zero)
(Notice that 'true' means 'non-zero' when we're checking a
given value, but it means '1' when we're producing a new one.)
Read through the chapter again in the light of this
revelation, making sure that it all works.
In the expressions x AND y, x OR y and NOT x, x and y will
usually take the values 0 and 1 for false and true. Work out
the ten different combinations (four for AND, four for OR and
two for NOT) and check that they do what the chapter leads you
to expect them to do.
Try this program:
10 INPUT a
20 INPUT b
30 PRINT (a AND a>=b)+(b AND a<b)
40 GO TO 10
Each time it prints the larger of the two numbers a and b.
Convince yourself that you can think of
x AND y
as meaning
x if y (else the result is 0)
and of
x OR y
as meaning
x unless y (in which case the result is 1)
An expression using AND or OR like this is called a
conditional expression. An example using OR could be
LET total price=price less tax*(1.15 OR
v$="zero rated")
Notice how AND tends to go with addition (because its default
value is 0), and OR tends to go with multiplication (because
its default value is 1).
You can also make string valued conditional expressions, but
only using AND.
x$ AND y has the value {x$ if y is non-zero
{"" if y is zero
so it means x$ if y (else the empty string).
Try this program, which inputs two strings and puts them in
alphabetical order.
10 INPUT "type in two strings"'a$,b$
20 IF a$>b$ THEN LET c$=a$: LET a$=b$: LET b$=c$
30 PRINT a$;" ";("<" AND a$<b$)+("=" AND a$=b$);" ";b$
40 GO TO 10
Exercise
1. BASIC can sometimes work along different lines from English.
Consider, for instance, the English clause 'If a doesn't equal
b or c'. How would you write this in BASIC? The answer is not
IF A<>B OR C
nor is it
IF A<>B OR A<>C
CHAPTER 14
The Character Set
Summary
CODE, CHR$
POKE, PEEK
USR
BIN
The letters, digits, punctuation marks and so on that can
appear in strings are called characters, and they make up the
alphabet, or character set, that the ZX Spectrum uses. Most of
these characters are single symbols, but there are some more,
called tokens, that represent whole words, such as PRINT, STOP
, <> and so on.
There are 256 characters, and each one has a code between 0
and 255. There is a complete list of them in Appendix A. To
convert between codes and characters, there are two functions,
CODE and CHR$.
CODE is applied to a string, and gives the code of the first
character in the string (or 0 if the string is empty).
CHR$ is applied to a number, and gives the single character
string whose code is that number.
This program prints out the entire character set:
10 FOR a=32 TO 255: PRINT CHRS a;: NEXT a
At the top you can see a space, 15 symbols and punctuation
marks, the ten digits, seven more symbols, the capital letters,
six more symbols, the lower case letters and five more symbols.
These are all (except ú and ) taken from a widely-used set of
characters known as ASCII (standing for American Standard
Codes for Information Interchange); ASCII also assigns numeric
codes to these characters, and these are the codes that the ZX
Spectrum uses.
The rest of the characters are not part of ASCII, and are
peculiar to the ZX Spectrum. First amongst them are a space and
15 patterns of black and white blobs. These are called the
graphics symbols and can be used for drawing pictures. You can
enter these from the keyboard, using what is called graphics
mode. If you press GRAPHICS (CAPS SHIFT with 9) then the cursor
will change to
G. Now the keys for the digits 1 to 8 will give the graphics
symbols: on their own they give the symbols drawn on the keys;
and with either shift pressed they give the same symbol but
inverted, i.e. black becomes white, and vice versa.
Regardless of shifts, digit 9 takes you back to normal (L)
mode and digit 0
is DELETE.
After the graphics symbols, you will see what appears to be
another copy of the alphabet from A to U. These are characters
that you can redefine yourself. although when the machine is
first switched on they are set as letters - they are called
user-defined graphics. You can type these in from the keyboard
by going into graphics mode, and then using the letters keys
from A to U.
To define a new character for yourself, follow this recipe -
it defines a character to show p.
(i) Work out what the character looks like. Each character has
an 8x8 square of dots, each of which can show either the paper
colour or the ink colour (see the introductory booklet). You'd
draw a diagram something like this, with black squares for the
ink colour:
We've left a 1 square margin round the edge because the other
letters all have one (except for lower case letters with tails,
where the tail goes right down to the bottom).
(ii) Work out which user-defined graphic is to show n- let's
say the one corresponding to P, so that if you press P in
graphics mode you get p.
(iii) Store the new pattern. Each user-defined graphic has its
pattern stored as eight numbers, one for each row. You can
write each of these numbers as BIN followed by eight 0's or 1
's - 0 for paper, 1 for ink - so that the eight numbers for
our p character are
BIN 00000000
BIN 00000000
BIN 00000010
BIN 00111100
BIN 01010100
BIN 00010100
BIN 00010100
BIN 00000000
(If you know about binary numbers, then it should help you to
know that BIN is used to write a number in binary instead of
the usual decimal.)
These eight numbers are stored in memory, in eight places,
each of which has an address. The address of the first byte, or
group of eight digits, is USR "P" (P because that is what we
chose in (ii)), that of the second is USR "P" +1, and so on up
to the eighth, which has address USR "P"+7.
USR here is a function to convert a string argument into the
address of the first byte in memory for the corresponding
user-defined graphic. The string argument must be a single
character which can be either the user-defined graphic itself
or the corresponding letter (in upper or lower case). There is
another use for USR, when its argument is a number, which will
be dealt with.
Even if you don't understand this, the following program will
do it for you
:
10 FOR n=0 TO 7
20 INPUT row: POKE USR "P"+n,row
30 NEXT n
It will stop for INPUT data eight times to allow you to type
in the eight BIN numbers above - type them in the right order,
starting with the top row.
The POKE statement stores a number directly in memory
location, bypassing the mechanisms normally used by the BASIC.
The opposite of POKE is PEEK, and this allows us to look at the
contents of a memory location although it does not actually
alter the contents of that location. They will be dealt with
properly in Chapter 24.
After the user-defined graphics come the tokens.
You will have noticed that we have not printed out the first
32 characters, with codes 0 to 31. These are control
characters. They don't produce anything printable, but have
some less tangible effect on the television, or they are used
for controlling something other than the television, and the
television prints ? to show that it doesn't understand them.
They are described more fully in Appendix A.
Three that the television uses are those with codes 6, 8 and
13; on the whole, CHR$ 8 is the only one you are likely to find
useful.
CHR$ 6 prints spaces in exactly the same way as a comma does
in a PRINT statement for instance
PRINT 1; CHR$ 6;2
does the same as
PRINT 1,2
Obviously this is not a very clear way of using it. A more
subtle way is to
say
LET a$="1"+CHR$ 6+"2"
PRINT a$
CHR$ 8 is 'backspace': it moves the print position back one
place - try
PRINT "1234"; CHR$ 8;"5"
which prints up 1235
CHR$ 13 is 'newline': it moves the print position on to the
beginning of the next line.
The television also uses those with codes 16 to 23; these are
explained in Chapters 15 and 16. All the control characters are
listed in Appendix A.
Using the codes for the characters we can extend the concept
of 'alphabetical ordering' to cover strings containing any
characters, not just letters. If instead of thinking in terms
of the usual alphabet of 26 letters we use the extended
alphabet of 256 characters, in the same order as their codes,
then the principle is exactly the same. For instance, these
strings are in their ZX Spectrum alphabetical order. (Notice
the rather odd feature that lower case letters come after all
the capitals: so "a" comes after "Z"; also, spaces matter.)
CHR$ 3+"ZOOLOGICAL GARDENS"
CHR$ 8+"AARDVARK HUNTING"
"AAAARGH!"
"(Parenthetical remark)"
"100"
"129.95 inc. VAT"
"AASVOGEL"
"Aardvark"
"PRINT"
"Zoo"
"[interpolationl"
"aardvark"
"aasvogel"
"zoo"
"zoology
Here is the rule for finding out which order two strings come
in. First, compare the first characters. If they are different,
then one of them has its code less than the other, and the
string it came from is the earlier (lesser) of the two strings.
If they are the same, then go on to compare the next
characters. If in this process one of the strings runs out
before the other, then that string is the earlier, otherwise
they must be equal.
The relations =, <, >, <=, >= and <> are used for strings as
well as for numbers: < means 'comes before' and > means 'comes
after', so that
"AA man"<"AARDVARK"
"AARDVARK">"AA man"
are both true.
<= and >= work the same way as they do for numbers, so that
"The same string"<="The same string"
is true, but
"The same string"<"The same string"
is false.
Experiment on all this using the program here, which inputs
two strings and puts them in order.
10 INPUT "Type in two strings:", a$, b$
20 IF a$>b$ THEN LET c$=a$: LET a$=b$: LET b$=c$
30 PRINT a$;" ";
40 IF a$<b$ THEN PRINT "<";: GO TO 60
50 PRINT "="
60 PRINT " ";b$
70 GO TO 10
Note how we have to introduce c$ in line 20 when we swap over
a$ and b$,
LET a$=b$: LET b$=a$
would not have the desired effect.
This program sets up user-defined graphics to show chess
pieces:
P for pawn
R for rook
N for knight
B for bishop
K for king
Q for queen
Chess pieces:
5 LET b=BIN 01111100: LET c=BIN 00111000: LET d=BIN
00010000
10 FOR n=1 TO 6: READ p$: REM 6 pieces
20 FOR f=0 TO 7: REM read piece into 8 bytes
30 READ a: POKE USR p$+f,a
40 NEXT f
50 NEXT n
100 REM bishop
110 DATA "b",0,d, BIN 00101000,BIN 01000100
120 DATA BIN 01101100,c,b,0
130 REM king
140 DATA "k",0,d,c,d
150 DATA c, BIN 01000100,c,0
160 REM rook
170 DATA "r",0, BIN 01010100,b,c
180 DATA c,b,b,0
190 REM queen
200 DATA "q",0, BIN 01010100, BIN 00101000,d
210 DATA BIN 01101100,b,b,0
220 REM pawn
230 DATA "p",0,0,d,c
240 DATA c,d,b,0
250 REM knight
260 DATA "n",0,d,c, BIN 01111000
270 DATA BIN 00011000,c,b,0
Note that 0 can be used instead of BIN 00000000.
When you have run the program, look at the pieces by going
into graphics mode.
Exercises
1. Imagine the space for one symbol divided up into four
quarters like a Battenburg cake. Then if each quarter can be
either black or white, there are 2x2x2x2=16 possibilities. Find
them all in the character set.
2. Run this program:
10 INPUT a
20 PRINT CHR$ a;
30 GO TO 10
If you experiment with it, you'll find that CHR$ a is rounded
to the nearest whole number; and if a is not in the range 0 to
255 then the program stops with error report B integer out of
range.
3. Which of these two is the lesser?
"EVIL"
"evil"
4. Work out how to modify the program to set up user-defined
graphics so that it uses READ and DATA statements instead of
the INPUT statement.
CHAPTER 15
More about PRINT and INPUT
Summary
CLS
PRINT items: nothing at all
Expressions (numeric or string type): TAB numeric
expression, AT numeric
expression, numeric expression
PRINT separators: ,; '
INPUT items: variables (numeric or string type)
LINE string variable
Any PRINT item not beginning with a letter. (Tokens are
not considered a
s beginning with a letter.)
Scrolling.
SCREEN$
You have already seen PRINT used quite a lot, so you will
have a rough idea of how it is used. Expressions whose values
are printed are called PRINT items, and they are separated by
commas or semicolons, which are called PRINT separators. A
PRINT item can also be nothing at all, which is a way of
explaining what happens when you use two commas in a row.
There are two more kinds of PRINT items, which are used to
tell the computer not what, but where to print. For example
PRINT AT 11,16;"*" prints a star in the middle of the screen.
AT line, column
moves the PRINT position (the place where the next item is to
be printed) to the line and column specified. Lines are
numbered from 0 (at the top) to 21, and columns from 0 (on the
left) to 31.
SCREEN$ is the reverse function to PRINT AT, and will tell
you (within limits) what character is at a particular position
on the screen. It uses line and column numbers in the same way
as PRINT AT, but enclosed in brackets: for instance
PRINT SCREEN$ (11,16)
will retrieve the star you printed in the paragraph above.
Characters taken from tokens print normally, as single
characters, and spaces return as spaces. Lines drawn by PLOT,
DRAW or CIRCLE, user-defined characters and graphics characters
return as a null (empty) string, however. The same applies if
OVER has been used to create a composite character.
TAB column
prints enough spaces to move the PRINT position to the column
specified. It stays on the same line. or, if this would involve
backspacing, moves on to the next one. Note that the computer
reduces the column number 'modulo 32' (it divides by 32 and
takes the remainder); so TAB 33 means the same as TAB 1.
As an example,
PRINT TAB 30;1;TAB 12;"Contents"; AT 3,1;"CHAPTER";TAB
24;"page"
is how you might print out the heading of a contents page on
page 1 of a book
.
Try running this:
10 FOR n=8 TO 23
20 PRINT TAB 8*n;n;
30 NEXT n
This shows what is meant by the TAB numbers being reduced
modulo 32.
For a more elegant example, change the 8 in line 20 to a 6.
Some small points:
(i) These new items are best terminated with semicolons, as we
have done above. You can use commas (or nothing, at the end of
the statement), but this means that after having carefully set
up the PRINT position you immediately move it on again not
usually terribly useful.
(ii) You cannot print on the bottom two lines (22 and 23) on
the screen because they are reserved for commands, INPUT data,
reports and so on. References to 'the bottom line' usually mean
line 21.
(iii) You can use AT to put the PRINT position even where there
is already something printed; the old stuff will be obliterated
when you print more.
Another statement connected with PRINT is CLS. This clears
the whole screen , something that is also done by CLEAR and
RUN.
When the printing reaches the bottom of the screen, it starts
to scroll upwards rather like a typewriter. You can see this if
you do
CLS: FOR n=1 TO 22: PRINT n: NEXT n
and then do
PRINT 99
a few times.
If the computer is printing out reams and reams of stuff,
then it takes great care to make sure that nothing is scrolled
off the top of the screen until you have had a chance to look
at it properly. You can see this happening if you type
CLS: FOR n=1 TO 100: PRINT n: NEXT n
When it has printed a screen full, it will stop, writing
scroll? at the bottom of the screen. You can now inspect the
first 22 numbers at your leisure. When you have finished with
them, press y (for 'yes') and the computer will give you
another screen full of numbers. Actually, any key will make the
computer carry on except n (for 'no'), STOP (SYMBOL SHIFT and
a), or SPACE (the BREAK key). These will make the computer stop
running the program with a report D BREAK - CONT repeats.
The INPUT statement can do much more than we have told you so
far. You have already seen INPUT statements like
INPUT "How old are you?", age
in which the computer prints the caption How old are you? At
the bottom of the screen, and then you have to type in your
age.
In fact, an INPUT statement is made up of items and
separators in exactly the same way as a PRINT statement is, so
How old are you? and age are both INPUT items. INPUT items are
generally the same as PRINT items, but there are some very
important differences.
First, an obvious extra INPUT item is the variable whose
value you are to type in age in our example above. The rule is
that if an INPUT item begins with a letter, it must be a
variable whose value is to be input.
Second, this would seem to mean that you can't print out the
values of variables as part of a caption; however, you can get
round this by putting brackets round the variable. Any
expression that starts with a letter must be enclosed in
brackets if it is to be printed as part of a caption.
Any kind of PRINT item that is not affected by these rules is
also an INPUT item. Here is an example to illustrate what's
going on:
LET my age = INT (RND * 100): INPUT ("I am ";my age; ".
");"How old are you?", your age
my age is contained in brackets, so its value gets printed out.
Your age is not contained in brackets, so you have to type its
value in.
Everything that an INPUT statement writes goes to the bottom
part of the screen, which acts somewhat independently of the
top half. In particular, its lines are numbered relative to the
top line of the bottom half, even if this has moved up the
actual television screen (which it does if you type lots and
lots of INPUT data).
To see how AT works in INPUT statements, try running this:
10 INPUT "This is line 1.",a$; AT 0,0;"This is line 0.",a$;
AT 2,0; "This is line 2.",a$; AT 1,0; "This is still line
1.",a$
(just press ENTER each time it stops.) When This is line 2. is
printed, the lower part of the screen moves up to make room for
it; but the numbering moves up as well, so that the lines of
text keep their same numbers.
Now try this:
10 FOR n=0 TO 19: PRINT AT n,0;n;: NEXT n
20 INPUT AT 0,0;a$; AT 1,0;a$; AT 2,0;a$; AT 3,0;a$; AT
4,0;a$; AT 5,0;a$;
As the lower part of the screen goes up and up, the upper
part is undisturbed until the lower part threatens to write on
the same line as the PRINT position. Then the upper part starts
scrolling up to avoid this.
Another refinement to the INPUT statement that we haven't
seen yet is called LINE input and is a different way of
inputting string variables. If you write LINE before the name
of a string variable to be input, as in
INPUT LINE a$
then the computer will not give you the string quotes that it
normally does for a string variable, although it will pretend
to itself that they are there.
So if you type in
cat
as the INPUT data, a$ will be given the value cat. Because the
string quotes do not appear on the string, you cannot delete
them and type in a different sort of string expression for the
INPUT data. Remember that you cannot use LINE for numeric
variables.
The control characters CHR$ Z and CHR$ 23 have effects rather
like AT and TAB. They are rather odd as control characters,
because whenever one is sent to the television to be printed,
it must be followed by two more characters that do not have
their usual effect: they are treated as numbers (their codes)to
specify the line and column (for AT) or the tab position (for
TAB). You will almost always find it easier to use AT and TAB
in the usual way rather than the control characters, but they
might be useful in some circumstances. The AT control
character is CHR$ 22. The first character after it specifies
the line number and the second the column number, so that
PRINT CHR$ 22+CHR$ 1 +CHR$ c;
has exactly the same effect as
PRINT AT 1,c;
This is so even if CHR$ 1 or CHR$ c would normally have a
different meaning (for instance if c=13); the CHR$ 22 before
them overrides that.
The TAB control character is CHR$ 23 and the two characters
after it are used to give a number between 0 and 65535
specifying the number you would have in a TAB item:
PRINT CHRS 23+CHRS a+CHRS b;
has the same effect as
PRINT TAB a+256*b;
You can use POKE to stop the computer asking you scroll? by
doing
POKE 23692,255
every so often. After this it will scroll up 255 times before
stopping with scroll?. As an example, try
10 FOR n=0 TO 10000
20 PRINT n: POKE 23692,255
30 NEXT n
and watch everything whizz off the screen!
Exercises
1. Try this program on some children, to test their
multiplication tables.
10 LET m$=" "
20 LET a=INT (RND*12)+1: LET b=lNT (RND*12)+1
30 INPUT (m$) ' ' "what is ";(a) ";(b);"?";c
100 IF c=a-b THEN LET m$="Right.": GO TO 20
110 LET m$=''Wrong. Try again.": GO TO 30
If they are perceptive, they might manage to work out that
they do not have to do the calculation themselves. For
instance, if the computer asks them to type the answer to 2*3,
all they have to type in is 2*3.
One way of getting round this is to make them input strings
instead of numbers. Replace c in line 30 by c$. and in line 100
by VAL c$, and insert a line
40 IF c$<> STR$ VAL c$ THEN LET m$="Type it properly,
as a number,":
GO TO 30
That will fool them. After a few more days, however, one of
them may discover that they can get round this by rubbing out
the string quotes and typing in STR$ (2*3). To stop up this
loophole, you can replace c$ in line 30 by LINE c$.
CHAPTER 16
Colours
Summary
INK, PAPER, FLASH, BRIGHT, INVERSE, OVER
BORDER
Run this program:
10 FOR m=4 TO 1: BRIGHT m
20 FOR n=1 TO 14
30 FOR c=4 TO 7
40 PAPER c: PRINT " ";: REM 4 coloured spaces
50 NEXT c: NEXT n: NEXT m
60 FOR m=0 TO 1: BRIGHT m: PAPER 7
70 FOR c=0 TO 3
80 INK c: PRINT c;" ";
90 NEXT c: PAPER 0
100 FOR c=4 T0 7
110 INK c: PRINT c;" ";
120 NEXT c: NEXT m
130 PAPER 7: INK 0: BRIGHT 0
This shows the eight colours (including white and black) and
the two levels of brightness that the ZX Spectrum can produce
on a colour television. (If you r television is black and
white, then you will just see various shades of grey.) Here is
a list of them for reference; they are also written over the
appropriate number keys.
0 - black
1 - blue
2 - red
3 - purple, or magenta
4 - green
5 - pale blue, technically called cyan
6 - yellow
7 - white
On a black and white television, these numbers are in order
of brightness.
To use these colours properly, you need to understand a bit
about how the picture is arranged.
The picture is divided up into 768 (24 lines of 32) positions
where characters can be printed, and each character is printed
as an 8x8 square of dots like that below for a. This should
remind you of the user-defined graphics in Chapter 14, where we
had 0s for the white dots and 1s for the black dots.
The character position also has associated with it two
colours: the ink, or foreground colour, which is the colour
for the black dots in our square, and the paper, or background
colour, which is used for the white dots. To start off with,
every position has black ink and white paper so writing appears
as black on white.
The character position also has a brightness (normal or extra
bright) and something to say whether it flashes or not -
flashing is done by swapping the ink and paper colours. This
can all be coded into numbers, so a character position then has
(i) an 8x8 square of 0s and 1 s to define the shape of the
character, with 0 for paper and 1 for ink,
(ii) ink and paper colours, each coded into a number between 0
and 7,
(iii) a brightness - 0 for normal, 1 for extra bright and
(iv) a flash number - 0 for steady, 1 for flashing.
Note that since the ink and paper colours cover a whole
character position, you cannot possibly have more than two
colours in a given block of 64 dots. The same goes for the
brightness and flash number: they refer to the whole character
position, not individual dots. The colours, brightness and
flash number at a given position are called attributes.
When you print something on the screen, you change the dot
pattern at that position; it is less obvious, but still true,
that you also change the attributes at that position. To start
off with you do not notice this because everything is printed
with black ink on white paper (and normal brightness and no
flashing), but you can vary this with the INK, PAPER, BRIGHT
and FLASH statements. Try
PAPER 5
and then print a few things: they will all appear on cyan
paper, because as they are printed the paper colours at the
positions they occupy are set to cyan (which has code 5).
The others work the same way, so after
PAPER number between 0 and 7
INK number between 0 and 7
BRIGHT 0 or 1 } Think of 0 as off
or } and 1 as on
FLASH 0 or 1 }
any printing will set the corresponding attribute at all the
character positions it uses. Try some of these out. You should
now be able to see how the program at the beginning worked
(remember that a space is a character that has INK and PAPER
the same colour).
There are some more numbers you can use in these statements
that have less direct effects.
8 can be used in all four statements, and means 'transparent'
in the sense that the old attribute shows through. Suppose, for
instance, that you do
PAPER 8
No character position will ever have its paper colour set to
8 because there is no such colour; what happens is that when a
position is printed on, its paper colour is left the same as it
was before. INK 8, BRIGHT 8 and FLASH 8 work the same way for
the other attributes.
9 can be used only with PAPER and INK, and means 'contrast'.
The colour (ink or paper) that you use it with is made to
contrast with the other by being made white if the other is a
dark colour (black, blue, red or magenta), and black if the
other is a light colour (green, cyan, yellow or white).
Try this by doing
INK 9: FOR c=0 TO 7: PAPER c: PRINT c: NEXT c
A more impressive display of its power is to run the program
at the beginning to make coloured stripes, and then doing
INK 9: PAPER 8: PRINT AT 0,8;: FOR n=l TO 1080: PRINT
n;: NEXT n
The ink colour here is always made to contrast with the old
paper colour at each position.
Colour television relies on the rather curious fact that the
human eye can only really see three colours - the primary
colours, blue, red and green. The other colours are mixtures
of these. For instance, magenta is made by mixing blue with
red - which is why its code, 3, is the sum of the codes for
blue and red.
To see how all eight colours fit together, imagine three
rectangular spotlights, coloured blue, red and green, shining
at not quite the same place on a piece of white paper in the
dark. Where they overlap you will see mixtures of colours, as
shown by this program (note that ink spaces are obtained by
using either SHIFT with 8 when in G mode):
10 BORDER 0: PAPER 0: INK 7: CLS
20 FOR a=1 TO 6
30 PRINT TAB 6; INK 1; "nnnnnnnnnnnnnnnnnn": REM 18 ink
squares
40 NEXT a